package cn.ww.teach.knowledge.ocr;

import net.sourceforge.tess4j.Tesseract;
import net.sourceforge.tess4j.TesseractException;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;

/**
 * Created by Wangwang on 2017/11/26.
 */
public class OcrTest {
    public static void main(String[] args) throws TesseractException, IOException {
        Tesseract tesseract = new Tesseract();
        tesseract.setDatapath("D:\\project\\mvnPrj\\src\\main\\resources\\dev\\tessdata");
        tesseract.setLanguage("chi_sim");
        File file = new File("C:\\Users\\lenovo\\Desktop\\test.png");
        //File file = new File("C:\\Users\\lenovo\\Desktop\\testa.png");
        String s = tesseract.doOCR(file);
        //String s = tesseract.doOCR(imageFileHandler(file));

        System.out.println(new String(s.getBytes(), "GBK"));
        System.out.println(        System.getProperty("file.encoding"));
        System.out.println(System.getProperty("sun.jnu.encoding"));

        //byte[] bytes = s.getBytes();
        //String result = StringUtils.newString(bytes, "utf-8");
        //System.out.println(result);
    }

    private void changeEncode() throws IOException {
          /*文件由ANSI转化为UTF - 8
                * 需要用到流InputStreamReader和OutputStreamWriter
                * 这两个流有charset功能
                **/
        File srcFile = new File("D:\\project\\mvnPrj\\src\\main\\resources\\dev\\tessdata\\");
        File destFile = new File("/home/cwjy1202/hadoop/javaTest/dali01_000_CWJ000.txt");
        InputStreamReader isr = new InputStreamReader(new FileInputStream(srcFile), "GBK"); //ANSI编码
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(destFile), "UTF-8"); //存为UTF-8

        int len = isr.read();
        while (-1 != len) {

            osw.write(len);
            len = isr.read();
        }
        //刷新缓冲区的数据，强制写入目标文件
        osw.flush();
        osw.close();
        isr.close();
    }

    private static File imageFileHandler(File file) throws IOException {
        BufferedImage read = ImageIO.read(file);
        BufferedImage bufferedImage = replaceWithWhiteColor(read);
        ImageIO.write(bufferedImage, "png", new File("C:\\Users\\lenovo\\Desktop\\result.png"));
        return new File("C:\\Users\\lenovo\\Desktop\\result.png");
    }
//    public int[] detectFace(String imageFileName) {
//        int[] RectPosition = new int[4];
//        CascadeClassifier faceDetector = new CascadeClassifier("lbpcascade_frontalface.xml");
//        Mat image = Highgui.imread(imageFileName);
//        MatOfRect faceDetections = new MatOfRect();
//        //指定人脸识别的最大和最小像素范围
//        Size minSize = new Size(120, 120);
//        Size maxSize = new Size(250, 250);
////参数设置为scaleFactor=1.1f, minNeighbors=4, flags=0 以此来增加识别人脸的正确率
//        faceDetector.detectMultiScale(image, faceDetections, 1.1f, 4, 0, minSize, maxSize);
//        //对识别出来的头像画个方框，并且返回这个方框的位置坐标和大小
//        for (Rect rect : faceDetections.toArray()) {
//            Core.rectangle(image, new Point(rect.x, rect.y), new Point(rect.x
//                    + rect.width, rect.y + rect.height), new Scalar(0, 255, 0));
//            RectPosition[0] = rect.x;
//            RectPosition[1] = rect.y;
//            RectPosition[2] = rect.width;
//            RectPosition[3] = rect.height;
//            System.out.println(rect.x + " " + rect.y + " " + rect.width + " " + rect.height);
//        }
//// 下面注释掉的三行可以用来生成识别出的人脸图像，保存下来以便Debug用
////          String filename = "face.png";
////          System.out.println(String.format("Writing %s", filename));
////          Highgui.imwrite(filename, image);
//        return RectPosition;
//    }

    //　Tesseract-OCR对身份证上的字体识别率比较低的问题。Tesseract自带的chi_sim.traineddatad（识别库）对身份证上字体的识别率偏低，想了很多办法，
//
//    也用了很多时间精力去用身份证专用的华文细黑字体库来做训练(关于如何使用jTessBoxEditor-1.2来生成tif图片和矫正每个字体的识别，还有如何用命令行进行训练生成tessdata识别库的问题，学到的经验多到几乎可以写一大篇文档了。这个要等有时间再总结了)，捣腾了很多次之后发现出来的tessdata并没有比原生自带的chi_sim识别率提高多少，可能是需要从大到小不同字体都进行训练才行。
//
//            4.　　身份证照片解析度不高，1600x1200的摄像头照出来的效果不敢恭维而且身份证相片上面有很多弧形干扰线导致识别率更加低
//
//    为了提高解析度消除干扰线，我用了Tess4J自带的ImageHelper.convertImageToBinary()把图像处理成黑白照片，一次性解决了字体受干扰的问题，不过由照片上笔画比较多的字体笔画间隙出现了模糊，我在转换黑背之前加上了一个图像处理的步骤，消除字体笔画间隙的干扰让字体更加清晰，方法如下：
//
    private static BufferedImage replaceWithWhiteColor(BufferedImage bi) {
        int[] rgb = new int[3];
        int width = bi.getWidth();
        int height = bi.getHeight();
        int minx = bi.getMinX();
        int miny = bi.getMinY();
        /**
         * 遍历图片的像素，为处理图片上的杂色，所以要把指定像素上的颜色换成目标白色 用二层循环遍历长和宽上的每个像素
         */
        int hitCount = 0;
        for (int i = minx; i < width - 1; i++) {
            for (int j = miny; j < height; j++) {
                /**
                 * 得到指定像素（i,j)上的RGB值，
                 */
                int pixel = bi.getRGB(i, j);
                int pixelNext = bi.getRGB(i + 1, j);
                /**
                 * 分别进行位操作得到 r g b上的值
                 */
                rgb[0] = (pixel & 0xff0000) >> 16;
                rgb[1] = (pixel & 0xff00) >> 8;
                rgb[2] = (pixel & 0xff);
                /**
                 * 进行换色操作，我这里是要换成白底，那么就判断图片中rgb值是否在范围内的像素
                 */
//经过不断尝试，RGB数值相互间相差15以内的都基本上是灰色，
//对以身份证来说特别是介于73到78之间，还有大于100的部分RGB值都是干扰色，将它们一次性转变成白色
                if ((Math.abs(rgb[0] - rgb[1]) < 15)
                        && (Math.abs(rgb[0] - rgb[2]) < 15)
                        && (Math.abs(rgb[1] - rgb[2]) < 15) &&
                        (((rgb[0] > 73) && (rgb[0] < 78)) || (rgb[0] > 100))) {
                    //进行换色操作,0xffffff是白色
                    bi.setRGB(i, j, 0xffffff);
                }
            }
        }
        return bi;
    }
}
